import * as _ from 'lodash';
import * as THREE from "three";
import { parseShape, forceArray } from './utils'
import { TRAFFIC_LIGHTS } from './materials'
const Directions = {
  LEFT: 'l',  // 左
  RIGHT: 'r', // 右
  STRAIGHT: 's',  // 直
  UTURN: 't',   // 掉头
  PARTIAL_LEFT: 'L', // 部分左
  PARTIAL_RIGHT: 'R',  // 部分右
}

export default class TrafficLights {
  /** 不同方向的信号灯模型对象 */
  arrows;
  /** 所有的信号灯 */
  lightObjects = {};
  constructor(init) {
    this.arrows = init.arrows;
    this.currentPrograms = {}
    this.lightCycles = {}
  }
  loadNetwork(self) {
    const { net } = self.init.network
    const transform = self.transform
    const group = new THREE.Group()
    group.name = 'TrafficLightGroup'
    /**  找到所有包含‘t1’的对象，连接车道的数据
      dir ： 方向
      from ：来自那个道路
      fromLane : 道路的车道编号
      linkIndex:  和交叉口相关
      shate: 信号控制的类型，包含但不限于红黄绿等信号灯光
            “o”=黄色闪烁，“y” = 黄色小调，“Y” = 黄色大调，“r” = 红色，“g” = 绿色小调，“G”绿色大调
      tl ：信号灯的id，有交叉口才有该数据
      to: 要去的道路
      toLane: 道路的车道编号
      via：交叉口id
    */
    const tlConnections = _.filter(net.connection, c => _.has(c, 'tl'));
    const lightCounts = {};
    // 将对象的id作为key，对象作为值，edge是道路信息
    /**
      function: "internal"
      id: ":  道路id
      lane: [  道路信息
        {
          id: ":车道id
          index: 车道编号
          length: 车道长度
          shape: 车道点位
          speed: 车道速度
        }
      ] 
    */
    const edgeIdToEdge = _.keyBy(net.edge, 'id');

    _.forEach(tlConnections, (connection) => {
      const lightId = connection.tl; // id
      const { dir } = connection;  // 方向
      // 拿到当前连接道路对应的车道信息 lane
      const lanes = forceArray(edgeIdToEdge[connection.from].lane);  // 传入参数输出为数组
      // 拿到当前车道是来自于那个道路的车道
      const lane = lanes[Number(connection.fromLane)];
      const laneId = lane.id;

      // 记下车道上所有灯的数量，这样我们就可以抵消它们的高度
      // { ":a0_0" : 1}
      lightCounts[laneId] = (lightCounts[laneId] || 0) + 1;

      // 获取每个车道的信号灯方向的模型
      const light = this.getObjectForDirection(dir).clone();
      const name = `Light ${lightId} ${laneId} ${dir}`;
      light.traverse(obj => {
        obj.name = name;
        // 添加一个类型，这样灯光就会包含在datastore.clickedObjects中
        // 通过userData 给模型添加自定义字段
        obj.userData = {
          type: 'light',
        };
      });
      // 车道的点位，二维数组 [[1838.6, 842.35],[1839.96, 842.93]]
      const shape = parseShape(lane.shape);

       // 将sumo的左手坐标转换成three的右手坐标
       const [x, y , z] = transform.xyToXyz(shape[shape.length - 1]);
       const [px, , pz] = transform.xyToXyz(shape[shape.length - 2]);
       // 使用车道的最后2个点来确定光线的角度 -2.0344439
       const yRotation = Math.atan2(z - pz, px - x);
       light.position.set(x, y + lightCounts[laneId], z);
       light.rotation.set(0, yRotation, 0);
       group.add(light);
       if (!this.lightObjects[lightId]) {
         this.lightObjects[lightId] = [];
       }
       this.lightObjects[lightId][Number(connection.linkIndex)] = light;
    })
    return group
  }
  // 获取车道方向对应的模型
  getObjectForDirection(dir) {
    if (dir === Directions.LEFT || dir === Directions.PARTIAL_LEFT) {
      return this.arrows.left;
    } else if (dir === Directions.RIGHT || dir === Directions.PARTIAL_RIGHT) {
      return this.arrows.right;
    } else if (dir === Directions.STRAIGHT) {
      return this.arrows.straight;
    } else if (dir === Directions.UTURN) {
      return this.arrows.uturn;
    } else {
      throw new Error(`Unknown turn direction: ${dir}.`);
    }
  }
  addLogic(tlLogics) {
    _.forEach(_.groupBy(tlLogics, 'programID'), (programLogics, programId) => {
      
      this.lightCycles[programId] = _.keyBy(programLogics, 'id');
    });
    
  }
  setLightProgram(lightId, programId) {
    this.currentPrograms[lightId] = programId;
  }
  // 设置信号灯材质颜色
  setPhase(lightId, phaseIndex) {
    const programId = this.currentPrograms[lightId];
    const lightCycle = this.lightCycles[programId][lightId];
    if (!lightCycle) {
      console.warn('Cannot set phase for light', lightId);
      return;
    }
    const lightState = lightCycle.phase[phaseIndex].state; // this is a string like 'rgyR'
    const lights = this.lightObjects[lightId];
    lights.forEach((light, i) => {
      const material = TRAFFIC_LIGHTS[lightState.charAt(i).toLowerCase()] || TRAFFIC_LIGHTS.x;
      light.traverse(child => {
        if (child.isMesh) {
          child.material = material;
        }
      });
    });
  }
}